/*
 * Speck cipher implementation and testing code
 * (c) 2013 by Sebastian Gesemann
 *
 * Speck is a family of lightweight block ciphers designed by a team
 * of NSA members (see http://eprint.iacr.org/2013/404.pdf )
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

// This file shows you how you can use the Speck cipher C++11 implementation

#include <iostream>
#include <iomanip>
#include <sstream>
#include "speck.hpp"

template<int N>
std::ostream& operator<<(std::ostream& os, speck::block_t<N> const& s)
{
	using std::setw;
	std::ostringstream ss;
	ss.setf(std::ios::hex,std::ios::basefield);
	ss.fill('0');
	ss << '('  << setw((N+3)/4) << s.x;
	ss << ", " << setw((N+3)/4) << s.y << ')';
	return os << ss.str();
}

int main()
{
	// Speck always uses 2 words for a block and 2<=M<=4 words for a key.
	// All the word sizes (16,24,32,48 and 64) are supported.
	const int N = 32; // wordsize N (in bits)
	const int M = 4;  // number of word keys
	typedef speck::block_t<N> block_t; // pair of words (x,y)
	speck::key_t<N,M> key = {{
		0x3210, 0x7654, 0xBA98, 0xFEDC
	}};
	auto subkeys = key_expand(key); // subkeys array
	block_t block = {23,41};
	std::cout << "N=" << N << ", " << block << " encrypted using some " << M << "-word-key\n";
	encrypt(block,subkeys);
	std::cout << "   is " << block;
	std::cout << ". And when we decrypt it we\n";
	decrypt(block,subkeys);
	std::cout << "  get " << block << " again.\n";
	return 0;
}
